package com.iot.ammeter.network

import android.accounts.NetworkErrorException
import android.util.Log
import android.widget.Toast
import com.iot.ammeter.IApplication
import com.iot.ammeter.model.Response1
import com.iot.ammeter.model.parcelable.DeviceInfo
import com.iot.ammeter.model.parcelable.LastMonthInfo
import com.iot.ammeter.model.parcelable.UserInfo
import com.iot.ammeter.network.services.AuthService
import com.iot.ammeter.network.services.BaseDataService
import kotlinx.coroutines.*
import retrofit2.Call
import retrofit2.HttpException
import retrofit2.await
import java.lang.Exception

/**
 * 等待网络请求结果，并处理失败请求
 */
object NetworkHelper {

    private val networkDispatcher = Dispatchers.IO
    private val uiDispatcher = Dispatchers.Main
    private val BaseDataService = ServiceCreator.create<BaseDataService>()
    private val AuthService = ServiceCreator.create<AuthService>()

    /**
     * 网络状态逻辑处理函数，统一异常捕获处理
     * @param onFailure 请求失败时回调
     */
    suspend fun <T> withLogic(
        onRequest: suspend CoroutineScope.() -> T,
        onSuccess: (T) -> Unit,
        onFailure: () -> Unit,
        onFinished: (Boolean) -> Unit = {}
    ) = withContext(uiDispatcher) {
        var success = false
        try {
            val data = onRequest()
            onSuccess(data)
            success = true
        } catch (networkException: NetworkErrorException) {
            showErrorToast("网络错误")
        } catch (httpException: HttpException) {
            showErrorToast("网络请求失败")
        } catch (apiException: APIFailException) {
            Log.d("|", "--------------- 请求失败 ---------------")
            Log.d("|", "错误码：${apiException.code}")
            Log.d("|", "错误信息：${apiException.message}")
            Log.d("|", "---------------------------------------")
            showErrorToast(apiException.message!!)
        } catch (e: Exception) {
            showErrorToast("未知异常")
            e.printStackTrace()
        } finally {
            if (!success) onFailure()
            onFinished(success)
        }
    }

    private suspend fun showErrorToast(message: String) {
        withContext(uiDispatcher) {
            Toast.makeText(IApplication.context, message, Toast.LENGTH_SHORT).show()
        }
    }

    private suspend fun <D : ResponseData, R : ResponseWrap<D>> Call<R>.awaitData(): D {
        val responseWrap = this.await()
        return if (responseWrap.success) {
            responseWrap.data!!
        } else throw APIFailException(responseWrap.code, responseWrap.message)
    }

    suspend fun getUserInfo(token: String): UserInfo =
        BaseDataService.getUserInfo(token).awaitData()

    suspend fun getDeviceInfo(deviceId: String): DeviceInfo =
        BaseDataService.getDeviceInfo(deviceId).awaitData()

    suspend fun getLastMonthInfo(userId: String, deviceId: String?): LastMonthInfo =
        BaseDataService.getLastMonthInfo(userId, deviceId).awaitData()

    suspend fun tryLogin(email: String, password: String): String =
        AuthService.login(email, password).awaitData().v1

    suspend fun toRegister(email: String, password: String, mailCode: String): String =
        AuthService.register(email, password, mailCode).awaitData().v1
}

